package com.qyer.search.model;

import static com.qyer.commons.utils.CommonUtils.cast2Int;
import static com.qyer.commons.utils.CommonUtils.cast2String;
import static com.qyer.search.model.PageInfo.buildPageInfo;
import static com.qyer.search.model.User.buildUser;
import static org.apache.commons.lang3.builder.ToStringStyle.SHORT_PREFIX_STYLE;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Sets;
import com.qyer.commons.utils.CommonUtils;
import com.qyer.search.Constants;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
/**
 * User: Z J Wu Date: 2016/01/07 Time: 10:53 Package: com.qyer.search.model
 */
public class SearchParameter {

  private static final Set<String> LOG_ESCAPE_PARAM = Sets
    .newHashSet("kw", "type1", "type2", "f_country_id", "f_city_id", "uid", "guid", "context", "source_place", "supplier_id");

  // 单个一级类目
  @JsonProperty
  private int type1;

  // 单个二级类目
  @JsonProperty
  private int type2;

  // 当个目的地国家id
  @JsonProperty
  private int destinationCountryId;

  // 单个目的地城市id
  @JsonProperty
  private int destinationCityId;

  //出发地id
  @JsonProperty
  private int setOutPlaceId;

  //供应商id
  @JsonProperty
  private int supplierId;

  @JsonProperty
  private String destination;

  @JsonProperty
  private String destCountry;

  // 用户输入的关键词
  @JsonProperty
  private String userInputKW;
  @JsonProperty
  private int topic;
  @JsonProperty
  private int poi;
  @JsonProperty
  private int start_city;
  @JsonProperty
  private int travel_day;
  @JsonProperty
  private Set<Integer> topicids;
  ///////+++++++++++++
  private int continentId;
  private String continent;
  //////++++++++++++++

  // 额外附加参数
  @JsonProperty("additional_params")
  private Map<String, Object> conditions;

  @JsonIgnore
  private String context;
  @JsonIgnore
  private String requestId;
  @JsonIgnore
  private User user;
  @JsonIgnore
  private PageInfo pageInfo;

  public SearchParameter() {
    this.context = "inner-test";
    this.requestId = CommonUtils.getRequestId();
  }

  public SearchParameter(int type1, int type2, int destinationCountryId, int destinationCityId,
                         int setOutPlaceId, int supplierId, String userInputKW,
                         Map<String, Object> conditions, String context, String requestId,
                         User user, PageInfo pageInfo, String destination) {
    this.type1 = type1;
    this.type2 = type2;
    this.destinationCountryId = destinationCountryId;
    this.destinationCityId = destinationCityId;
    this.setOutPlaceId = setOutPlaceId;
    this.supplierId = supplierId;
    this.userInputKW = userInputKW;
    this.conditions = conditions;
    this.context = context;
    this.requestId = requestId;
    this.user = user;
    this.pageInfo = pageInfo;
    this.destination = destination;
  }

  public SearchParameter(int type1, int type2, int destinationCountryId, int destinationCityId,
                         int setOutPlaceId, int supplierId, String userInputKW,
                         Map<String, Object> conditions, String context, String requestId,
                         User user, PageInfo pageInfo, String destination, String destCountry) {
    this.type1 = type1;
    this.type2 = type2;
    this.destinationCountryId = destinationCountryId;
    this.destinationCityId = destinationCityId;
    this.setOutPlaceId = setOutPlaceId;
    this.supplierId = supplierId;
    this.userInputKW = userInputKW;
    this.conditions = conditions;
    this.context = context;
    this.requestId = requestId;
    this.user = user;
    this.pageInfo = pageInfo;
    this.destination = destination;
    this.destCountry = destCountry;
  }

  public SearchParameter(int type1, int type2, int destinationCountryId, int destinationCityId,
                         int setOutPlaceId, int supplierId, String userInputKW,
                         Map<String, Object> conditions, String context, String requestId,
                         User user, PageInfo pageInfo, String destination, String destCountry,int topic, int poi) {
    this.type1 = type1;
    this.type2 = type2;
    this.destinationCountryId = destinationCountryId;
    this.destinationCityId = destinationCityId;
    this.setOutPlaceId = setOutPlaceId;
    this.supplierId = supplierId;
    this.userInputKW = userInputKW;
    this.conditions = conditions;
    this.context = context;
    this.requestId = requestId;
    this.user = user;
    this.pageInfo = pageInfo;
    this.destination = destination;
    this.destCountry = destCountry;
    this.topic = topic;
    this.poi = poi;
  }

  public SearchParameter(int type1, int type2, int destinationCountryId, int destinationCityId,
                         int setOutPlaceId, int supplierId, String userInputKW,
                         Map<String, Object> conditions, String context, String requestId,
                         User user, PageInfo pageInfo, String destination, String destCountry,
                         Set<Integer> topic, int poi, int start_city, int travel_day) {
    this.type1 = type1;
    this.type2 = type2;
    this.destinationCountryId = destinationCountryId;
    this.destinationCityId = destinationCityId;
    this.setOutPlaceId = setOutPlaceId;
    this.supplierId = supplierId;
    this.userInputKW = userInputKW;
    this.conditions = conditions;
    this.context = context;
    this.requestId = requestId;
    this.user = user;
    this.pageInfo = pageInfo;
    this.destination = destination;
    this.destCountry = destCountry;
    this.poi = poi;
    this.topicids = topic;
    this.start_city = start_city;
    this.travel_day = travel_day;
  }

  public SearchParameter(int type1, int type2, int destinationCountryId, int destinationCityId,
                         int setOutPlaceId, int supplierId, String userInputKW,
                         Map<String, Object> conditions, String context, String requestId,
                         User user, PageInfo pageInfo, String destination, String destCountry,
                         Set<Integer> topic, int poi, int start_city, int travel_day, String continent) {
    this.type1 = type1;
    this.type2 = type2;
    this.destinationCountryId = destinationCountryId;
    this.destinationCityId = destinationCityId;
    this.setOutPlaceId = setOutPlaceId;
    this.supplierId = supplierId;
    this.userInputKW = userInputKW;
    this.conditions = conditions;
    this.context = context;
    this.requestId = requestId;
    this.user = user;
    this.pageInfo = pageInfo;
    this.destination = destination;
    this.destCountry = destCountry;
    this.poi = poi;
    this.topicids = topic;
    this.start_city = start_city;
    this.travel_day = travel_day;
    this.continent = continent;
  }

  public SearchParameter(HttpServletRequest req) {
    this.context = cast2String(req.getParameter("context"));
    this.type1 = cast2Int(req.getParameter("type1"));
    this.type2 = cast2Int(req.getParameter("type2"));
    this.destinationCountryId = cast2Int(req.getParameter("f_country_id"));
    this.destinationCityId = cast2Int(req.getParameter("f_city_id"));
    this.userInputKW = cast2String(req.getParameter("kw"));

    String setOutString = cast2String(req.getParameter("source_place"));
    this.setOutPlaceId = -1;
    if(StringUtils.isNotBlank(setOutString)){
      setOutString = setOutString.trim();
      if(Constants.START_POS_MAP.containsKey(setOutString))
        setOutPlaceId = Constants.START_POS_MAP.get(setOutString);
    }

    this.supplierId = cast2Int(req.getParameter("supplier_id"));

    if (StringUtils.isNotBlank(this.userInputKW)) {
      this.userInputKW = this.userInputKW.toLowerCase();
    }
    this.requestId = CommonUtils.getRequestId();
    this.user = buildUser(req);
    this.pageInfo = buildPageInfo(req);

    Map parameterMap = req.getParameterMap();
    if (MapUtils.isEmpty(parameterMap)) {
      this.conditions = Collections.emptyMap();
    } else {
      this.conditions = new HashMap<>(5);
      Set<Map.Entry> s = parameterMap.entrySet();
      String k;
      Object valueObject;
      for (Map.Entry entry : s) {
        k = entry.getKey().toString().toLowerCase();
        if (LOG_ESCAPE_PARAM.contains(k)) {
          continue;
        }
        valueObject = entry.getValue();
        if (valueObject == null) {
          continue;
        }
        if (valueObject.getClass().isArray()) {
          Object[] objArr = (Object[]) valueObject;
          if (objArr != null && objArr.length == 1) {
            conditions.put(k, String.valueOf(objArr[0]));
          } else {
            conditions.put(k, objArr);
          }
        } else {
          conditions.put(k, String.valueOf(valueObject));
        }
      }
    }
  }

  public int getConditionCacheKey() {
    int result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    if(!StringUtils.isBlank(destination))
      result = 31 * result + destination.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(destCountry))
      result = 31 * result + destCountry.hashCode();
    else
      result = 31 * result + 0;
    return result;
  }

  public long getConditionCacheKeyLong() {
    long result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    if(!StringUtils.isBlank(destination))
      result = 31 * result + destination.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(destCountry))
      result = 31 * result + destCountry.hashCode();
    else
      result = 31 * result + 0;
    return result;
  }

  public long getConditionCacheKeyLong2() {
    long result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    if(!StringUtils.isBlank(destination))
      result = 31 * result + destination.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(destCountry))
      result = 31 * result + destCountry.hashCode();
    else
      result = 31 * result + 0;
    if(topic != -1){
      result = 31 * result + topic;
    }else {
      result = 31 * result + 0;
    }
    if(poi != -1){
      result = 31 * result + poi;
    }else {
      result = 31 * result;
    }
    return result;
  }

  public long getZCacheKey() {
    long result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    if(!StringUtils.isBlank(destination))
      result = 31 * result + destination.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(destCountry))
      result = 31 * result + destCountry.hashCode();
    else
      result = 31 * result + 0;
    result = 31 * result + poi;
    result = 31 * result + start_city;
    result = 31 * result + travel_day;
    if(CollectionUtils.isNotEmpty(topicids)) {
      List<Integer> tmp = new ArrayList<>(topicids);
      Collections.sort(tmp);
      result = 31 * result + tmp.hashCode();
      /*for(int ta:tmp) {
        result = 31 * result + ta;
      }*/
    }
    return result;
  }

  public long getZCacheKey2() {
    long result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    if(!StringUtils.isBlank(destination))
      result = 31 * result + destination.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(destCountry))
      result = 31 * result + destCountry.hashCode();
    else
      result = 31 * result + 0;

    if(!StringUtils.isBlank(continent))
      result = 31 * result + continent.hashCode();
    else
      result = 31 * result + 0;

    result = 31 * result + poi;
    result = 31 * result + start_city;
    result = 31 * result + travel_day;
    if(CollectionUtils.isNotEmpty(topicids)) {
      List<Integer> tmp = new ArrayList<>(topicids);
      Collections.sort(tmp);
      result = 31 * result + tmp.hashCode();
      /*for(int ta:tmp) {
        result = 31 * result + ta;
      }*/
    }
    return result;
  }

  public String getContinent() {
    return continent;
  }

  public void setContinent(String continent) {
    this.continent = continent;
  }

  public int getContinentId() {
    return continentId;
  }

  public void setContinentId(int continentId) {
    this.continentId = continentId;
  }

  public Set<Integer> getTopicids() {
    return topicids;
  }

  public void setTopicids(Set<Integer> topicids) {
    this.topicids = topicids;
  }

  public int getTravel_day() {
    return travel_day;
  }

  public void setTravel_day(int travel_day) {
    this.travel_day = travel_day;
  }

  public int getStart_city() {
    return start_city;
  }

  public void setStart_city(int start_city) {
    this.start_city = start_city;
  }

  public int getType1() {
    return type1;
  }

  public void setType1(int type1) {
    this.type1 = type1;
  }

  public int getType2() {
    return type2;
  }

  public void setType2(int type2) {
    this.type2 = type2;
  }

  public int getDestinationCountryId() {
    return destinationCountryId;
  }

  public void setDestinationCountryId(int destinationCountryId) {
    this.destinationCountryId = destinationCountryId;
  }

  public int getDestinationCityId() {
    return destinationCityId;
  }

  public void setDestinationCityId(int destinationCityId) {
    this.destinationCityId = destinationCityId;
  }

  public String getUserInputKW() {
    return userInputKW;
  }

  public void setUserInputKW(String userInputKW) {
    this.userInputKW = userInputKW;
  }

  public String getContext() {
    return context;
  }

  public void setContext(String context) {
    this.context = context;
  }

  public String getRequestId() {
    return requestId;
  }

  public void setRequestId(String requestId) {
    this.requestId = requestId;
  }

  public User getUser() {
    return user;
  }

  public void setUser(User user) {
    this.user = user;
  }

  public PageInfo getPageInfo() {
    return pageInfo;
  }

  public void setPageInfo(PageInfo pageInfo) {
    this.pageInfo = pageInfo;
  }

  public Map<String, Object> getConditions() {
    return conditions;
  }

  public void setConditions(Map<String, Object> conditions) {
    this.conditions = conditions;
  }

  public int getSetOutPlaceId() {
    return setOutPlaceId;
  }

  public void setSetOutPlaceId(int setOutPlaceId) {
    this.setOutPlaceId = setOutPlaceId;
  }

  public int getSupplierId() {
    return supplierId;
  }

  public void setSupplierId(int supplierId) {
    this.supplierId = supplierId;
  }

  public String getDestination() {
    return destination;
  }

  public void setDestination(String destination) {
    this.destination = destination;
  }

  public String getDestCountry() {
    return destCountry;
  }

  public void setDestCountry(String destCountry) {
    this.destCountry = destCountry;
  }

  public int getTopic() {
    return topic;
  }

  public void setTopic(int topic) {
    this.topic = topic;
  }

  public int getPoi() {
    return poi;
  }

  public void setPoi(int poi) {
    this.poi = poi;
  }

  public boolean hasCityDest(){
    if(this.destination != null)
      return true;
    return false;
  }
  @Override public String toString() {
    return new ToStringBuilder(this, SHORT_PREFIX_STYLE).append("type1", type1)
                                                        .append("type2", type2)
                                                        .append("destinationCountryId",
                                                                destinationCountryId)
                                                        .append("destinationCityId",
                                                                destinationCityId)
                                                        .append("setOutPlace",setOutPlaceId)
                                                        .append("supplierId",supplierId)
                                                        .append("userInputKW", userInputKW)
                                                        .append("context", context)
                                                        .append("requestId", requestId)
                                                        .append("user", user)
                                                        .append("pageInfo", pageInfo)
                                                        .append("conditions", conditions)
                                                        .toString();
  }

  public boolean isCategory(){
    if((type2 == 0) && (setOutPlaceId == -1) && (destinationCityId == 0)
      && (destinationCountryId == 0) && (supplierId == 0) && StringUtils.isEmpty(userInputKW)
      && StringUtils.isEmpty(destination) && (type1 != 0) && StringUtils.isEmpty(destCountry)
      && (topic == 0))
      return true;
    if((type1 == 0) && (setOutPlaceId == -1) && (destinationCityId == 0)
      && (destinationCountryId == 0) && (supplierId == 0) && StringUtils.isEmpty(userInputKW)
      && StringUtils.isEmpty(destination) && (type2 != 0) && StringUtils.isEmpty(destCountry)
      && (topic == 0))
      return true;
    return false;
  }

  public boolean is10168Category(){
    if((type2 == 0) && (setOutPlaceId == -1) && (destinationCityId == 0)
      && (destinationCountryId == 0) && (supplierId == 0) && StringUtils.isEmpty(userInputKW)
      && StringUtils.isEmpty(destination) && (type1 == 1016 || type1 == 1018))
      return true;
    return false;
  }

  public boolean isHoelCategory(){
    //System.out.println("isHoelCategory");
    if((type2 == 0) && (setOutPlaceId == -1) && (destinationCityId == 0)
      && (destinationCountryId == 0) && (supplierId == 0) && StringUtils.isEmpty(userInputKW)
      && StringUtils.isNotEmpty(destination) && (type1 == 1017)) {
      //System.out.println("hotel");
      return true;
    }
    return false;
  }

  public SearchParameter newObject(){
    return new SearchParameter(0, 0, destinationCountryId, destinationCityId, setOutPlaceId,
                               supplierId, userInputKW, conditions, context, requestId, user,
                               pageInfo, destination, destCountry);
  }

  public SearchParameter newObject2(){
    return new SearchParameter(0, 0, destinationCountryId, destinationCityId, setOutPlaceId,
                               supplierId, userInputKW, conditions, context, requestId, user,
                               pageInfo, destination, destCountry, -1, -1);
  }

  @Override public boolean equals(Object o) {
    if (this == o)
      return true;
    if (o == null || getClass() != o.getClass())
      return false;

    SearchParameter that = (SearchParameter) o;

    if (type1 != that.type1)
      return false;
    if (type2 != that.type2)
      return false;
    if (destinationCountryId != that.destinationCountryId)
      return false;
    if (destinationCityId != that.destinationCityId)
      return false;
    if (setOutPlaceId != that.setOutPlaceId)
      return false;
    if (supplierId != that.supplierId)
      return false;
    if (topic != that.topic)
      return false;
    if (poi != that.poi)
      return false;
    if (start_city != that.start_city)
      return false;
    if (travel_day != that.travel_day)
      return false;
    if (!destination.equals(that.destination))
      return false;
    if (!destCountry.equals(that.destCountry))
      return false;
    if (!userInputKW.equals(that.userInputKW))
      return false;
    if (!topicids.equals(that.topicids))
      return false;
    if (!conditions.equals(that.conditions))
      return false;
    if (!context.equals(that.context))
      return false;
    if (!requestId.equals(that.requestId))
      return false;
    if (!user.equals(that.user))
      return false;
    return pageInfo.equals(that.pageInfo);

  }

  @Override public int hashCode() {
    int result = type1;
    result = 31 * result + type2;
    result = 31 * result + destinationCountryId;
    result = 31 * result + destinationCityId;
    result = 31 * result + setOutPlaceId;
    result = 31 * result + supplierId;
    result = 31 * result + destination.hashCode();
    result = 31 * result + destCountry.hashCode();
    result = 31 * result + poi;
    result = 31 * result + start_city;
    result = 31 * result + travel_day;
    result = 31 * result + topicids.hashCode();
    return result;
  }
}
